package com.szr.leex.common.ftp;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.SocketException;

import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * ftp util tool
 * Created by WangChen on 2017/7/24 13:48.
 */
public class FTPUtil {

    private Logger logger = LoggerFactory.getLogger(this.getClass());
    private String host;
    private int port;
    private String username;
    private String password;
    private boolean binaryMode = false;
    private boolean passiveMode = true;
    private FTPClient client;

    public static FTPUtil getInstance(){
        return new FTPUtil();
    }
    private FTPUtil(){}
    public FTPUtil(String host, int port, String username, String password){
        this.host = host;
        this.port = port;
        this.username = username;
        this.password = password;
    }
    public boolean isActive() {
        return client.isConnected();
    }

    public boolean connect() {
        client = new FTPClient();
        try {
            client.connect(host, port);
            client.login(username, password);
            //开启被动模式
            if (passiveMode) {
                client.enterLocalPassiveMode();
            }
            if (binaryMode) {
                client.setFileType(2);
            }
            //设置连接超时时间
            //client.setConnectTimeout(connectTimeout);
            int reply = client.getReplyCode();
            if (!FTPReply.isPositiveCompletion(reply)) {
                disconnect();
                logger.info("FTP server refused connection.");
            } else {
                logger.info("ftp connect to " + host + " success!");
            }
            return true;
        } catch (SocketException e) {
            logger.error("connect failed!", e);
        } catch (IOException e) {
            logger.error("connect failed!", e);
        }
        return false;
    }

    public boolean disconnect() {
        if (client.isConnected()) {
            try {
                client.logout();
                client.disconnect();
            } catch (IOException e) {
                logger.error("close failed!", e);
            }
            logger.info("ftp close connection!");
            return true;
        }
        return false;
    }

    public boolean upload(String localPath, String remotePath, String filename, String realName) {
        checkConnect();
        remotePath = formatPath(remotePath);
        localPath = formatPath(localPath);
        try {
            InputStream in = new FileInputStream(new File(localPath + filename));
            client.changeWorkingDirectory(remotePath);
            client.storeFile(filename, in);
            in.close();
            client.rename(filename, realName);
        } catch (IOException e) {
            logger.error("upload failed !", e);
            return false;
        }
        return true;
    }

    /**
     * download file
     */
    public boolean download(String remotePath, String localPath, String fileName) {
        checkConnect();
        remotePath = formatPath(remotePath);
        localPath = formatPath(localPath);
        boolean downloadFlag;
        try {
            OutputStream out = new FileOutputStream(new File(localPath + fileName));
            downloadFlag = client.retrieveFile(remotePath + fileName, out);
            out.flush();
            out.close();
        } catch (IOException e) {
            logger.error("download failed!", e);
            return false;
        }
        logger.debug("download file : " + fileName + ": "+ downloadFlag);
        return downloadFlag;
    }

    private void checkConnect() {
        if (client != null && client.isConnected()) {
            return;
        }
        if (client == null || disconnect()) {
            connect();
        }
    }

    public FTPFile[] listFiles(String remotePath, String fileName) {
        checkConnect();
        remotePath = formatPath(remotePath);
        try {
            return client.listFiles(remotePath + fileName);
        } catch (IOException e) {
            logger.error("ftp listFiles IOException:" + remotePath + fileName, e);
            throw new RuntimeException("ftp listFiles IOException:" + remotePath + fileName, e);
        }
    }

    /**
     * 校验remotePath路径下的文件fileName是否存在
     */
    public boolean checkExist(String remotePath, String fileName){
        checkConnect();
        FTPFile[] ftpFiles;
        ftpFiles = listFiles(remotePath, fileName);
        if (ftpFiles != null && ftpFiles.length > 0){
            return true;
        }
        return false;
    }

    public InputStream getInputStream(String remotePath, String fileName) throws IOException {
        checkConnect();
        return client.retrieveFileStream(formatPath(remotePath) + fileName);
    }
    /**
     * 格式化path，以/结束
     */
    private String formatPath(String path){
        if (null == path || "".equals(path)){
            return "";
        }
        if (!path.endsWith("/")){
            return path + "/";
        }
        return path;
    }

    public String getHost() {
        return host;
    }

    public FTPUtil setHost(String host) {
        this.host = host;
        return this;
    }

    public int getPort() {
        return port;
    }

    public FTPUtil setPort(int port) {
        this.port = port;
        return this;
    }

    public String getUsername() {
        return username;
    }

    public FTPUtil setUsername(String username) {
        this.username = username;
        return this;
    }

    public String getPassword() {
        return password;
    }

    public FTPUtil setPassword(String password) {
        this.password = password;
        return this;
    }

    public boolean isBinaryMode() {
        return binaryMode;
    }

    public FTPUtil setBinaryMode(boolean binaryMode) {
        this.binaryMode = binaryMode;
        return this;
    }

    public boolean isPassiveMode() {
        return passiveMode;
    }

    public FTPUtil setPassiveMode(boolean passiveMode) {
        this.passiveMode = passiveMode;
        return this;
    }
}
